#include <Arduino.h>
#include <WiFi.h>
#include <esp_core_dump.h>
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "./tools/kiss_fftr.h"


#include "audio.h"
#include "model.h"

#include "mfcc.h"

#include "RCSwitch.h"
RCSwitch sendSwitch = RCSwitch();




namespace {
tflite::ErrorReporter* error_reporter = nullptr;
const tflite::Model* model = nullptr;
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;
TfLiteTensor* output = nullptr;
int inference_count = 0;

constexpr int kTensorArenaSize = 65000;
//uint8_t tensor_arena[kTensorArenaSize];
uint8_t*tensor_arena;

}  // namespace

typedef struct 
{
  char*name;
  const uint16_t*data;
}UserLabel;

float*tensorInput;



//执行器运行的状态
int tensorFlowRunState=0;


int getMaxIndex(int8*data,int len){
  int index=0;
  int8 temp=0;
  for(int i=0;i<len;i++){
    if(data[i]>temp){
      temp=data[i];
      index=i;
    }
  }
  return index;
}

#define KZ 6
#define KISSSIZE 256


float*inputRecord;

int countIndex=0;
#define blockSize 256
uint16_t * data=NULL;
int ringIndex=0;
//int16_t record[512];
int16_t*record;
int16_t lastData=0;

#define LED_PIN 4

void setup() {
  Serial.begin(115200);
  Serial.println("setup");
  pinMode(26,OUTPUT);
  digitalWrite(26,HIGH);

  sendSwitch.enableTransmit(25);
  //sendSwitch.send(0x00230F21, 24);

  WiFi.begin("MERCURY_2AD7","15172442270");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("ip: ");
  Serial.println(WiFi.localIP());
  
  record=(int16_t*)malloc(512*sizeof(int16_t));


  static tflite::MicroErrorReporter micro_error_reporter;
  error_reporter = &micro_error_reporter;

  //加载模型
  model = tflite::GetModel(model_tflite);
  Serial.printf("model version:%d\r\n",model->version());
  if (model->version() != TFLITE_SCHEMA_VERSION) {
    TF_LITE_REPORT_ERROR(error_reporter,
                         "Model provided is schema version %d not equal "
                         "to supported version %d.",
                         model->version(), TFLITE_SCHEMA_VERSION);
    return;
  }

  tensor_arena=(uint8_t*)malloc(kTensorArenaSize);
  if(tensor_arena==NULL){
    Serial.println("mem free error!");
    return;
  }

  static tflite::AllOpsResolver resolver;
  //resolver.AddConv2D();
  //resolver.AddMaxPool2D();


  //初始化
  static tflite::MicroInterpreter static_interpreter(
      model, resolver, tensor_arena, kTensorArenaSize, error_reporter);
  //赋值给全局变量
  interpreter = &static_interpreter;

  //内存分配
  // Allocate memory from the tensor_arena for the model's tensors.
  TfLiteStatus allocate_status = interpreter->AllocateTensors();
  if (allocate_status != kTfLiteOk) {
    TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
    return;
  }
  Serial.printf("Free heap1: %d\n", esp_get_free_heap_size());
  //获取输入输出张量指针
  input = interpreter->input(0);
  tensorInput=input->data.f;
  output = interpreter->output(0);
  startAudio();
  fft_init();
  init_mel_filters();
  inputRecord=(float*)malloc(512*sizeof(float));
  Serial.println("--------------init-----------------");
  esp_core_dump_init();
  Serial.printf("Free heap2: %d\n", esp_get_free_heap_size());
}

int getAvg(int16_t *data,int size){
  int total=0;
  for(int i=0;i<size;i++){
    if(data[i]<0){
      total+= (-data[i]);
    }else{
      total+=data[i];
    }
  }
  return total/size;
}


#define Limitr 40
char ls[16]={0};
//命令的时间戳
long commandTime=0;
void loop(){
  
    long t1=micros();
    ringIndex=getRingIndex();
    float*out=tensorInput;
    //下面做mfcc变换
    lastData=0;
    for(int i=62;i>0;i--){
      getRingData(record,ringIndex-i*256,512);
      //做 预加重 算法
      for(int j=0;j<512;j++){

        if(j==0){
          //上次保留的值
          inputRecord[j]=record[j]*1.0 - 0.97 *lastData;
        }else if(i==1&&j>384){
          //最后几个填充0
          inputRecord[j]=0;
        }else{
          inputRecord[j]= record[j]*1.0 - 0.97 *record[j-1];
        }

        if(j<256){
          lastData=record[j];
        }
      }
      mfcc(inputRecord,out+(62-i)*13);
    }

    long tms1=micros();
    //Serial.printf("used time:%d , %d\r\n",tms1-t1,(tms1-t1)/1000);
    TfLiteStatus invoke_status = interpreter->Invoke();
  
    if (invoke_status != kTfLiteOk) {
      Serial.printf("Invoke failed on x: %f\r\n",2.0);
      return;
    }


   
    //Serial.println();
    int maxIndex=getMaxIndex(output->data.int8,output->dims->data[1]);
    if(maxIndex==0||maxIndex==2){
      //delay(50);
      //return;
    }

    if(maxIndex==4){
      commandTime=micros();
    }

    long ct=micros();
    //关灯
    if(commandTime!=0&&maxIndex==1&&(ct-commandTime)/(1000*1000)<5){
      //digitalWrite(26,HIGH);
      sendSwitch.send(0x00230F21, 24);
      Serial.println("hello close!");
    }else if(commandTime!=0&&maxIndex==3&&(ct-commandTime)/(1000*1000)<5){
      //digitalWrite(26,LOW);
      sendSwitch.send(0x00230F21, 24);
      Serial.println("hello open!");
    }


    //Serial.printf("scale:%f, zero_point:%d,input type:%d\r\n",output->params.scale,output->params.zero_point,output->type);
    Serial.printf("result:");

    for(int i=0;i<output->dims->data[1];i++){
        //uint8_t n0=0X00FF&output->data.uint8[i];
        int8_t t=output->data.int8[i];
       Serial.printf(" %d ",t);
    }
    Serial.println();
    long tm=micros();
    Serial.printf("name:%s,index:%d  %d\r\n\r\n",cmdName[maxIndex],maxIndex,tm-t1);
    delay(100);

    if(maxIndex!=4){
      //清除命令时间
      commandTime=0;
    }
}


